#include <lua5.4/lua.hpp>
#include <string>
#include <iostream>
#include "luaManager.h"

LuaManager::LuaManager(/* args */)
{
    m_lua = nullptr;
    m_funcMap.clear();
}

LuaManager::~LuaManager()
{
    if(m_lua) lua_close(m_lua);
}

/**
 * 初始化lua状态机的函数
 * @return 返回初始化结果
 */
bool LuaManager::Initialize(){
    // 1.创建lua状态机
    m_lua = luaL_newstate();
    if(!m_lua) return false;
    std::cout << "客户端成功创建lua虚拟机..." << std::endl;

    // 2.加载lua标准库
    luaL_openlibs(m_lua);

    // 3.加载系统需要暴露的函数(一定要在加载脚本入口前!!!)
    for (auto it = m_funcMap.begin(); it != m_funcMap.end(); ++it){
        if(!Register2Lua(it->first, it->second)){
            return false;// 有一个注册失败就返回
        }
    }
    std::cout << "客户端成功加载所需的函数..." << std::endl;

    // 4.加载lua脚本层入口函数
    if (luaL_dofile(m_lua, "../src/test/main.lua") != LUA_OK) {
        std::cout << "客户端加载脚本入口文件失败..." << std::endl;
        std::cerr << "Lua 错误: " << lua_tostring(m_lua, -1) << std::endl;  // 打印错误信息
        lua_pop(m_lua, 1);// 弹出错误信息,避免栈堆积
        lua_close(m_lua);
        return false;
    }
    return true;
}

/**
 * 往注册容器中添加待注册函数
 * @param name lua中调用的函数名称
 * @param callback 具体绑定的C++函数
 */
void LuaManager::PutNewExposeFunc(std::string name, luaCallback callback){
    m_funcMap.emplace(name, callback);
}

/**
 * 自行封装的向lua注册C函数
 * @return 返回成功与否
 * @param name lua中调用的函数名称
 * @param callback 具体绑定的C++函数
 */
bool LuaManager::Register2Lua(std::string name, luaCallback callback){
    lua_pushcfunction(m_lua, callback);
    lua_setglobal(m_lua, name.c_str());
    return true;
}

/**
 * 由C++调用lua函数
 */
void LuaManager::DoLuaFunc(const char* name, const char* data, size_t size){
    // 1.检查输入有效性
    if(!data || size == 0 || !m_lua) return;

    // 2.根据名称掉用处理函数
    lua_getglobal(m_lua, name);
    if (!lua_isfunction(m_lua, -1)){
        lua_pop(m_lua, 1); // 清理栈
        return;
    }

    // 3.推送参数（二进制）
    lua_pushlstring(m_lua, data, size);

    // 4.调用函数
    int ret = lua_pcall(m_lua, 1, 0, 0);
    if(ret != LUA_OK){
        lua_pop(m_lua, 1);// 清理错误信息
    }
}